Skip to content

Comments

Repeat ping requests & fix connection keep-alive#416

Open
dharjeezy wants to merge 16 commits intoparitytech:masterfrom
dharjeezy:dami/repeat-request-periodically
Open

Repeat ping requests & fix connection keep-alive#416
dharjeezy wants to merge 16 commits intoparitytech:masterfrom
dharjeezy:dami/repeat-request-periodically

Conversation

@dharjeezy
Copy link
Contributor

@dharjeezy dharjeezy commented Jul 19, 2025

This PR:

  1. Repeats ping requests instead of sending them only on connect.
  2. Reuses ping substreams (both inbound and outbound) for subsequent requests, as required by the spec. This is needed for smoldot compatibility.
  3. Fixes connection keep-alive logic that didn't work due to permit stored in the connection context holding strong reference to ProtocolCommand channel.

Closes #415

Copy link
Collaborator

@dmitry-markin dmitry-markin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, this is going in the right direction, but there should be a way to simplify the implementation by not introducing separate async tasks for inbound/outbound substreams and not adding command channels. It should be possible to implement polling of inbound substreams by putting them into FuturesUnordered or, may be, tokio_stream::StreamMap. The latter should be quite easy as there is maximum one inbound substream allowed from any remote peer as per ping spec: https://github.com/libp2p/specs/blob/master/ping/ping.md

@dmitry-markin
Copy link
Collaborator

Hey, this is going in the right direction, but there should be a way to simplify the implementation by not introducing separate async tasks for inbound/outbound substreams and not adding command channels. It should be possible to implement polling of inbound substreams by putting them into FuturesUnordered or, may be, tokio_stream::StreamMap. The latter should be quite easy as there is maximum one inbound substream allowed from any remote peer as per ping spec: https://github.com/libp2p/specs/blob/master/ping/ping.md

tokio_stream::StreamMap might not work because we need to also write to substream and not only poll it, but still there should be a way to simplify the code.

@dharjeezy
Copy link
Contributor Author

Hey, this is going in the right direction, but there should be a way to simplify the implementation by not introducing separate async tasks for inbound/outbound substreams and not adding command channels. It should be possible to implement polling of inbound substreams by putting them into FuturesUnordered or, may be, tokio_stream::StreamMap. The latter should be quite easy as there is maximum one inbound substream allowed from any remote peer as per ping spec: https://github.com/libp2p/specs/blob/master/ping/ping.md

tokio_stream::StreamMap might not work because we need to also write to substream and not only poll it, but still there should be a way to simplify the code.

@dmitry-markin can you check my current implementation

Copy link
Collaborator

@dmitry-markin dmitry-markin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey hey, nice use of SplitStream/SplitSink! I think what is missing is a cleaner separation between inbound and outbound substreams. On inbound substreams we should only respond to incoming pings, and on outbound send pings ourself. It would be better than relying on the presence of the time in the map, which can get screwed when we both send pings to a peer and receive pings from it.

@dharjeezy
Copy link
Contributor Author

Hey hey, nice use of SplitStream/SplitSink! I think what is missing is a cleaner separation between inbound and outbound substreams. On inbound substreams we should only respond to incoming pings, and on outbound send pings ourself. It would be better than relying on the presence of the time in the map, which can get screwed when we both send pings to a peer and receive pings from it.

i have done this now @dmitry-markin

@haikoschol
Copy link
Contributor

Out of scope for this PR but I noticed that ping::config::MAX_FAILURES is not used anywhere. Should we create an issue for that?

Copy link
Contributor

@haikoschol haikoschol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, I ran the following tests, using a litep2p listener and webrtc transport:

Dialer Listener -> Dialer Pings Dialer -> Listener Pings
libp2p
"minimal smoldot env"

The failing outbound pings with libp2p is an unrelated issue (#494).


/// Log target for the file.
const LOG_TARGET: &str = "litep2p::ipfs::ping";
const PING_TIMEOUT: Duration = Duration::from_secs(10);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const PING_TIMEOUT: Duration = Duration::from_secs(10);

Since it is unused. However, we probably want to have a timeout for receiving pongs. Arguably out of scope for this PR though.

@dharjeezy dharjeezy requested a review from haikoschol December 24, 2025 05:21
@dharjeezy dharjeezy requested a review from haikoschol January 18, 2026 17:49
@dharjeezy
Copy link
Contributor Author

@lexnv @haikoschol @dmitry-markin please help review

@haikoschol
Copy link
Contributor

@lexnv @haikoschol @dmitry-markin please help review

LGTM, but my approval doesn't count towards mergeability.

@dharjeezy dharjeezy requested a review from haikoschol February 21, 2026 12:54
@dmitry-markin
Copy link
Collaborator

Sorry for huge delay with reviewing. I have finally looked into the PR and tried to make it properly register protocols with appropriate keep-alive settings (dharjeezy-ping-keep-alive...dm-ping-keep-alive), but it turned out to be more tricky than I thought. The connection keep-alive mechanism relied on the fact that ping substreams were periodically opened, because the actual connection tear down happened only when somebody tried to open a new substream. With reused substreams it doesn't work anymore.

I am going to look further into this. Meanwhile, please don't push new changes to the PR. Thanks for all the work done so far!

@haikoschol
Copy link
Contributor

I am going to look further into this. Meanwhile, please don't push new changes to the PR. Thanks for all the work done so far!

FWIW, after testing with a full smoldot light client (as opposed to our minimal test env), I am pretty sure that merging this would increase stability of connections from smoldot to full nodes. I've included the changes in this PR in my branch that I've used for testing.

@dmitry-markin
Copy link
Collaborator

FWIW, after testing with a full smoldot light client (as opposed to our minimal test env), I am pretty sure that merging this would increase stability of connections from smoldot to full nodes. I've included the changes in this PR in my branch that I've used for testing.

Yes, smoldot needs a permanent ping substream (as per libp2p ping spec), or will disconnect litep2p on a second ping attempt trying to write to substream that was reset. This is why this issue is of a higher priority now.

@dmitry-markin dmitry-markin changed the title Repeat ping request periodically Repeat ping requests & fix connection keep-alive Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ping: repeat requests periodically

4 participants